package com.ranyk.www.util;

import com.ranyk.www.enums.PunctuationEnum;
import eu.bitwalker.useragentutils.Browser;
import eu.bitwalker.useragentutils.OperatingSystem;
import eu.bitwalker.useragentutils.UserAgent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.UnsupportedEncodingException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Objects;
import java.util.StringTokenizer;

/**
 * CLASS_NAME: ServletUtils.java <br/>
 *
 * @author ranyk           <br/>
 * @version V1.0           <br/>
 * @decription: ServletUtils工具类：提供一些Http与Servlet工具的方法  <br/>
 * @date: 2022-04-14 <br/>
 */
@Slf4j
@SuppressWarnings("unused")
public class ServletUtils {

    /**
     * 一千
     */
    private static final long ONE_THOUSAND = 1000;
    /**
     * unknown 字符串
     */
    private static final String UNKNOWN = "unknown";
    /**
     * 本机 IP V4 地址
     */
    private static final String LOCAL_IP_V4 = "127.0.0.1";
    /**
     * 本机 IP V6 地址
     */
    private static final String LOCAL_IP_V6 = "0:0:0:0:0:0:0:1";
    /**
     * 15
     */
    private static final int FIFTEEN = 15;
    /**
     * * 号
     */
    private static final String ASTERISK = "*";

    /**
     * 私有化无参构造器
     */
    private ServletUtils() {
        throw new AssertionError();
    }


    /**
     * 设置客户端缓存过期时间 的Header.
     *
     * @param response       {@link HttpServletResponse} 对象
     * @param expiresSeconds 过期时间,单位 秒
     */
    public static void setExpiresHeader(HttpServletResponse response, long expiresSeconds) {
        // Http 1.0 header
        response.setDateHeader("Expires", System.currentTimeMillis() + expiresSeconds * ONE_THOUSAND);
        // Http 1.1 header
        response.setHeader("Cache-Control", "private, max-age=" + expiresSeconds);
    }

    /**
     * 设置禁止客户端缓存的Header.
     *
     * @param response {@link HttpServletResponse} 对象
     */
    public static void setDisableCacheHeader(HttpServletResponse response) {
        // Http 1.0 header
        response.setDateHeader("Expires", 1L);
        response.addHeader("Pragma", "no-cache");
        // Http 1.1 header
        response.setHeader("Cache-Control", "no-cache, no-store, max-age=0");
    }

    /**
     * 设置LastModified Header.
     *
     * @param response         {@link HttpServletResponse} 对象
     * @param lastModifiedDate 最后修改时间,单位 秒
     */
    public static void setLastModifiedHeader(HttpServletResponse response, long lastModifiedDate) {
        response.setDateHeader("Last-Modified", lastModifiedDate * ONE_THOUSAND);
    }

    /**
     * 设置Etag Header.
     *
     * @param response {@link HttpServletResponse} 对象
     * @param etag     Etag 值
     */
    public static void setEtag(HttpServletResponse response, String etag) {
        response.setHeader("ETag", etag);
    }

    /**
     * 根据浏览器If-Modified-Since Header, 计算文件是否已被修改.如果无修改, checkIfModify返回false ,设置304 not modify status.
     *
     * @param request      {@link HttpServletRequest} 对象
     * @param response     {@link HttpServletResponse} 对象
     * @param lastModified 内容的最后修改时间.
     * @return 返回是否修改, 已修改返回  true;无修改返回 false
     */
    public static boolean checkIfModifiedSince(HttpServletRequest request, HttpServletResponse response, long lastModified) {
        long ifModifiedSince = request.getDateHeader("If-Modified-Since");
        if ((ifModifiedSince != -1) && (lastModified < ifModifiedSince + ONE_THOUSAND)) {
            response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
            return false;
        }
        return true;
    }

    /**
     * 根据浏览器 If-None-Match Header, 计算Etag是否已无效. 如果Etag有效, checkIfNoneMatch返回false, 设置304 not modify status.
     *
     * @param request  {@link HttpServletRequest} 对象
     * @param response {@link HttpServletResponse} 对象
     * @param etag     内容的ETag.
     * @return 返回 Etag 是否有效。有效返回 false;无效返回 true;
     */
    public static boolean checkIfNoneMatchEtag(HttpServletRequest request, HttpServletResponse response, String etag) {
        String headerValue = request.getHeader("If-None-Match");
        if (headerValue != null) {
            boolean conditionSatisfied = false;
            if (!ASTERISK.equals(headerValue)) {
                StringTokenizer commaTokenizer = new StringTokenizer(headerValue, ",");

                while (!conditionSatisfied && commaTokenizer.hasMoreTokens()) {
                    String currentToken = commaTokenizer.nextToken();
                    if (currentToken.trim().equals(etag)) {
                        conditionSatisfied = true;
                    }
                }
            } else {
                conditionSatisfied = true;
            }
            if (conditionSatisfied) {
                response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
                response.setHeader("ETag", etag);
                return false;
            }
        }
        return true;
    }

    /**
     * 设置让浏览器弹出下载对话框的Header.
     *
     * @param response {@link HttpServletResponse} 对象
     * @param fileName 下载后的文件名.
     */
    public static void setFileDownloadHeader(HttpServletResponse response, String fileName) {
        try {
            // 中文文件名支持
            String encodedFileName = new String(fileName.getBytes(), "ISO8859-1");
            response.setHeader("Content-Disposition", "attachment; filename=\"" + encodedFileName + "\"");
        } catch (UnsupportedEncodingException e) {
            log.error("ServletUtils.setFileDownloadHeader", e);
        }
    }

    /**
     * 获取当前请求对象
     *
     * @return 返回 {@link HttpServletRequest} 对象
     */
    public static HttpServletRequest getRequest() {
        return ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
    }

    /**
     * 获取项目名称路径
     *
     * @return 返回 content path 值
     */
    public static String getContentPath() {
        return getRequest().getContextPath();
    }

    /**
     * 获取项目绝对路径
     *
     * @return 返回项目的绝对路径
     */
    public static String getRealPath() {
        return getRequest().getSession().getServletContext().getRealPath("/");
    }

    /**
     * getAttribute这个方法是提取放置在某个共享区间的对象
     *
     * @param name 获取请求 session 中某个对象的 key
     * @return 返回获取到的对象值
     */
    public static Object getAttribute(String name) {
        return getRequest().getSession().getAttribute(name);
    }

    /**
     * getParameter系列的方法主要用于处理“请求数据”，是服务器端程序获取浏览器所传递参数的主要接口。
     *
     * @param name 需要获取的请求参数 key
     * @return 返回获取到的请求参数值
     */
    public static String getParameter(String name) {
        return getRequest().getParameter(name);
    }

    /**
     * getParameterValues这个方法是获得传过来的参数名相同的一个数组;
     *
     * @param name 获取请求参数的key
     * @return 返回获取到的参数值数组
     */
    public static String[] getParameterValues(String name) {
        return getRequest().getParameterValues(name);
    }

    /**
     * 获取当前网络ip
     *
     * @return 返回网络 IP 地址
     */
    public static String getIpAddress() {
        String ipAddress = getRequest().getHeader("x-forwarded-for");
        if (ipAddress == null || ipAddress.length() == 0 || UNKNOWN.equalsIgnoreCase(ipAddress)) {
            ipAddress = getRequest().getHeader("Proxy-Client-IP");
        }
        if (ipAddress == null || ipAddress.length() == 0 || UNKNOWN.equalsIgnoreCase(ipAddress)) {
            ipAddress = getRequest().getHeader("WL-Proxy-Client-IP");
        }
        if (ipAddress == null || ipAddress.length() == 0 || UNKNOWN.equalsIgnoreCase(ipAddress)) {
            ipAddress = getRequest().getRemoteAddr();
            if (LOCAL_IP_V4.equals(ipAddress) || LOCAL_IP_V6.equals(ipAddress)) {
                // 根据网卡取本机配置的IP
                InetAddress inet = null;
                try {
                    inet = InetAddress.getLocalHost();
                } catch (UnknownHostException e) {
                    log.error("ServletUtils.getIpAddress", e);
                }
                assert inet != null;
                ipAddress = inet.getHostAddress();
            }
        }
        // 对于通过多个代理的情况，第一个IP为客户端真实IP,多个IP按照','分割
        if (ipAddress != null && ipAddress.length() > FIFTEEN && ipAddress.indexOf(PunctuationEnum.comma.getValue()) > 0) {
            ipAddress = ipAddress.substring(0, ipAddress.indexOf(PunctuationEnum.comma.getValue()));
        }
        return ipAddress;
    }

    /**
     * 获取当前用户游览器信息
     *
     * @return 返回获取到浏览器 header 中 User-Agent 值
     */
    public static String getHeader() {
        return getRequest().getHeader("User-Agent");
    }

    /**
     * 获取当前用户游览器型号
     *
     * @return 返回获取到的浏览器型号
     */
    public static String getUserBrowser() {
        UserAgent userAgent = UserAgent.parseUserAgentString(getRequest().getHeader("User-Agent"));
        Browser browser = userAgent.getBrowser();
        return browser.toString();
    }

    /**
     * 获取当前用户系统型号
     *
     * @return 返回获取到的用户操作系统
     */
    public static String getUserOperatingSystem() {
        UserAgent userAgent = UserAgent.parseUserAgentString(getRequest().getHeader("User-Agent"));
        OperatingSystem operatingSystem = userAgent.getOperatingSystem();
        return operatingSystem.toString();
    }

}
